#import "AMapLocation.h"
#import <React/RCTUtils.h>

@interface AMapLocation ()
/**
 保存Promise的resolve block
 */
@property (nonatomic, copy) RCTPromiseResolveBlock resolveBlock;
/**
 保存Promise的reject block
 */
@property (nonatomic, copy) RCTPromiseRejectBlock rejectBlock;
@end

@implementation AMapLocation {
  AMapLocationManager *_manager;
  AMapLocationManager *locationManager;
  BOOL backRunning;
}

RCT_EXPORT_MODULE()

RCT_REMAP_METHOD(initLocation, key:(NSString *)key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
  //[[AMapServices sharedServices] setEnableHTTPS:YES];
  backRunning = NO;
   dispatch_async(dispatch_get_main_queue(), ^{
     [[AMapServices sharedServices] setEnableHTTPS:YES];
     [AMapServices sharedServices].apiKey = key;
       if (!locationManager) {
           locationManager = [AMapLocationManager new];
     }
       if (!_manager) {
           _manager = [AMapLocationManager new];
           _manager.distanceFilter = 200;
           _manager.delegate = self;
           _manager.locatingWithReGeocode = false;
         resolve(@1);
     } else {
         resolve(@1);
     }
   });
}

RCT_REMAP_METHOD(isBackgroundLocation, resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
  resolve(@(backRunning));
}

RCT_REMAP_METHOD(startForegroundLocation,
                foreLocationResolver:(RCTPromiseResolveBlock)resolve
                rejecter:(RCTPromiseRejectBlock)reject) {
  self.resolveBlock = resolve;
  self.rejectBlock = reject;
  [locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
  //   定位超时时间，最低2s，此处设置为2s
  locationManager.locationTimeout =2;
  //   逆地理请求超时时间，最低2s，此处设置为2s
  locationManager.reGeocodeTimeout = 2;
  [locationManager requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
      
      if (error)
      {
          NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
          
          if (error.code == AMapLocationErrorLocateFailed)
          {
            [self invokeError:error];
            return;
          }
      }
      
      NSLog(@"location:%@", location);
      
      if (regeocode)
      {
          NSLog(@"reGeocode:%@", regeocode);
      }
      id json = [self json:location reGeocode:regeocode type:1];
      [self invokeSuccessWithResult:json];
      // [self sendEventWithName:@"AMapGeolocation" body: json];
      // [NSUserDefaults.standardUserDefaults setObject:json forKey:AMapLocation.storeKey];
  }];
}

RCT_EXPORT_METHOD(startBackgroundLocation) {
  if(backRunning) {
    return;
  }
  [_manager setLocatingWithReGeocode:NO];
  [_manager startUpdatingLocation];
  backRunning = YES;
}

RCT_EXPORT_METHOD(stopBackgroundLocation) {
    [_manager stopUpdatingLocation];
  backRunning = NO;
}

RCT_EXPORT_METHOD(getLastLocation) {
    id json = [NSUserDefaults.standardUserDefaults objectForKey:AMapLocation.storeKey];
    [self sendEventWithName:@"AMapGeolocation" body: json];
}

-(long long)getDateTimeTOMilliSeconds:(NSDate *)datetime {
  NSTimeInterval interval = [datetime timeIntervalSince1970];
  NSLog(@"转换的时间戳=%f",interval);
  long long totalMilliseconds = interval*1000 ;
  NSLog(@"totalMilliseconds=%llu",totalMilliseconds);
  return totalMilliseconds;
}
                   
- (id)json:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode type:(int)type{
    if(!location) {
      return nil;
    }
    if (reGeocode && reGeocode.formattedAddress && reGeocode.formattedAddress.length) {
      return @{
          @"type":@(type),
          @"accuracy": @(location.horizontalAccuracy),
          @"latitude": @(location.coordinate.latitude),
          @"longitude": @(location.coordinate.longitude),
          @"altitude": @(location.altitude),
          @"speed": @(location.speed),
          @"direction": @(location.course),
          @"timestamp": @([self getDateTimeTOMilliSeconds:location.timestamp]),
          @"address": reGeocode.formattedAddress,
          @"poiName": reGeocode.POIName ? reGeocode.POIName : @(""),
          @"country": reGeocode.country ? reGeocode.country : @(""),
          @"province": reGeocode.province ? reGeocode.province : @(""),
          @"city": reGeocode.city ? reGeocode.city : @(""),
          @"cityCode": reGeocode.citycode ? reGeocode.citycode : @(""),
          @"district": reGeocode.district ? reGeocode.district : @(""),
          @"street": reGeocode.street ? reGeocode.street : @(""),
          @"streetNumber": reGeocode.number ? reGeocode.number : @(""),
          @"adCode": reGeocode.adcode ? reGeocode.adcode : @(""),
      };
    } else {
      return @{
          @"type":@(type),
          @"accuracy": @(location.horizontalAccuracy),
          @"latitude": @(location.coordinate.latitude),
          @"longitude": @(location.coordinate.longitude),
          @"altitude": @(location.altitude),
          @"speed": @(location.speed),
          @"direction": @(location.course),
          @"timestamp": @([self getDateTimeTOMilliSeconds:location.timestamp]),
      };
    }
}

- (void)amapLocationManager:(AMapLocationManager *)manager
          didUpdateLocation:(CLLocation *)location
                  reGeocode:(AMapLocationReGeocode *)reGeocode {
    NSLog(@"location:{lat:%f; lon:%f; accuracy:%f}", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy);
    if (reGeocode)
    {
        NSLog(@"reGeocode:%@", reGeocode);
    }
  id json = [self json:location reGeocode:reGeocode type:2];
    [self sendEventWithName:@"AMapGeolocation" body: json];
    [NSUserDefaults.standardUserDefaults setObject:json forKey:AMapLocation.storeKey];
}

- (NSArray<NSString *> *)supportedEvents {
    return @[@"AMapGeolocation"];
}

+ (NSString *)storeKey {
    return @"AMapGeolocation";
}

- (void)amapLocationManager:(AMapLocationManager *)manager doRequireLocationAuth:(CLLocationManager*)locationManager
{
    [locationManager requestAlwaysAuthorization];
}

- (void)invokeSuccessWithResult:(id) json {
    if (self.resolveBlock) {
        self.resolveBlock(json);
        self.resolveBlock = nil;
    }
}

- (void)invokeError:(NSError *)error {
    if (self.rejectBlock) {
      self.rejectBlock([NSString stringWithFormat: @"%ld", (long)error.code], error.localizedDescription, error);
      self.rejectBlock = nil;
    }
}

@end
